﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Globalization;
using System.Web;
using System.Web.Caching;
using TidyBlog.Data;
using TidyBlog.Entity;
using TidyBlog.DAL;

namespace TidyBlog.BLL
{
    /// <summary>
    /// 文章业务逻辑层
    /// </summary>
    public class ArticleBLL
    {
        /// <summary>
        /// 英文区域信息，用于格式化日期
        /// </summary>
        public static readonly CultureInfo DateCulture = CultureInfo.CreateSpecificCulture("zh-CN");

        /// <summary>
        /// 可见文章的最小权重
        /// </summary>
        protected const byte MinVisibleArticleWeight = 10;
        /// <summary>
        /// 推荐文章的最小权重
        /// </summary>
        protected const byte MinRecommendArticleWeight = 200;
        /// <summary>
        /// 文章目录页缓存名
        /// </summary>
        protected const string CACHENAME_INDEX = "ArticleHome-{0}";
        /// <summary>
        /// 推荐文章缓存名
        /// </summary>
        protected const string CACHENAME_RECOMMENDS = "RecommendArticles";
        /// <summary>
        /// 文章排行缓存名格式
        /// </summary>
        protected const string CACHENAME_TOPVIEW = "TopViewArticles-{0}";


        /// <summary>
        /// 验证文章属性
        /// </summary>
        /// <param name="article">文章</param>
        public static void Validate(Article article)
        {
            if (String.IsNullOrEmpty(article.Title))
            {
                throw new ArgumentException("标题不能为空");
            }

            if (article.SummarySize > 0 && (article.SummarySize < 50 || article.SummarySize > 5000))
            {
                throw new ArgumentException("摘要长度必须在50-5000之间");
            }

            if (article.State < 0 || article.State > 2)
            {
                throw new ArgumentException("错误的文章状态");
            }

            if (article.CategoryId > 0)
            {
                Category category = CategoryBLL.Read(article.CategoryId);
                if (category == null)
                {
                    throw new ArgumentException("分类不存在");
                }
                else
                {
                    article.CategoryName = category.CategoryName;
                }
            }
            else
            {
                throw new ArgumentException("分类不能为空");
            }

            article.Summary = BuildSummary(article.Content, article.SummarySize);
        }

        /// <summary>
        /// 生成文章摘要
        /// </summary>
        /// <param name="content">内容</param>
        /// <param name="summaryLength">摘要长度</param>
        /// <returns>摘要</returns>
        public static string BuildSummary(string content, short summaryLength)
        {
            if (String.IsNullOrEmpty(content)) { return String.Empty; }
            if (summaryLength <= 0) { return content; }

            string summary;

            if (content.Length <= summaryLength)    // 内容长度 <= 摘要长度，直接采用内容作为摘要
            {
                summary = content;
            }
            else
            {
                // 截取摘要
                summary = content.Substring(0, summaryLength);

                // 剔除开头不完全的HTML标记
                summary = Regex.Replace(summary, @"^[^<]*>", String.Empty);
                // 剔除末尾不完全的HTML标记
                summary = Regex.Replace(summary, @"<[^>]*$", String.Empty);
                // 剔除末尾的开始标记
                summary = Regex.Replace(summary, @"(?:<[^/][^<>]*[^/]>)+$", String.Empty);

                // 匹配双标签的开始标签
                MatchCollection beginTagMatches = Regex.Matches(
                    Regex.Replace(summary, @"<[^>]*/>", String.Empty), // 先去掉单标签
                    @"<([a-zA-Z0-9]+)[^>]*>"
                );
                // 匹配双标签的结束标签
                MatchCollection endTagMatches = Regex.Matches(summary, @"<\/([a-zA-Z0-9]+)>");

                // 记录开始标签、结束标签个数
                int beginTagCount = beginTagMatches.Count, endTagCount = endTagMatches.Count;


                if (beginTagCount > 0 || endTagCount > 0)
                {
                    List<string> beginTags = new List<string>(), endTags = new List<string>();
                    foreach (Match match in beginTagMatches)
                    {
                        beginTags.Add(match.Groups[1].Value);
                    }
                    foreach (Match match in endTagMatches)
                    {
                        endTags.Add(match.Groups[1].Value);
                    }
                    for (int i = 0, j; i < beginTagCount && endTags.Count > 0; i++)
                    {
                        for (j = 0; j < endTags.Count; j++)
                        {
                            if (beginTags[i] == endTags[j])
                            {
                                beginTags[i] = null;
                                endTags.RemoveAt(j);
                                break;
                            }
                        }
                    }

                    List<string> errBeginTags = new List<string>();
                    foreach (string tag in beginTags)
                    {
                        if (!String.IsNullOrEmpty(tag))
                        {
                            errBeginTags.Add(tag);
                        }
                    }

                    if (errBeginTags.Count > 0)
                    {
                        errBeginTags.Reverse();
                        summary += ("</" + String.Join("></", errBeginTags.ToArray()) + ">");
                    }
                    if (endTags.Count > 0)
                    {
                        summary = ("<" + String.Join("><", endTags.ToArray()) + ">") + summary;
                    }
                }
            }

            return summary;
        }

        /// <summary>
        /// 创建文章
        /// </summary>
        /// <param name="article">文章</param>
        /// <returns>文章编号</returns>
        public static int Create(Article article)
        {
            Validate(article);

            try
            {
                article.ArticleId = ArticleDAL.Create(article);
            }
            catch
            {
#if DEBUG
                throw;
#else
                throw new Exception("创建文章记录出错");
#endif
            }

            return article.ArticleId;
        }

        /// <summary>
        /// 更新文章
        /// </summary>
        /// <param name="article">文章</param>
        public static void Update(Article article)
        {
            Validate(article);

            try
            {
                ArticleDAL.Update(article);
            }
            catch
            {
#if DEBUG
                throw;
#else
                throw new Exception("更新文章记录出错");
#endif
            }
        }

        /// <summary>
        /// 读取文章
        /// </summary>
        /// <param name="articleId">文章编号</param>
        /// <returns>文章</returns>
        public static Article Read(int articleId)
        {
            Article article = null;

            try
            {
                article = ArticleDAL.Read(articleId);
            }
            catch
            {
#if DEBUG
                throw;
#else
                throw new Exception("读取文章出错");
#endif
            }

            return article;
        }
        
        /// <summary>
        /// 删除文章
        /// </summary>
        /// <param name="userId">文章编号</param>
        public static void Delete(int articleId)
        {
            try
            {
                ArticleDAL.Delete(articleId);
            }
            catch
            {
#if DEBUG
                throw;
#else
                throw new Exception("删除文章记录出错");
#endif
            }
        }

        /// <summary>
        /// 检查指定编号的文章是否存在
        /// </summary>
        /// <param name="articleId">文章编号</param>
        /// <returns>指定编号的文章是否存在</returns>
        public static bool IsExist(int articleId)
        {
        	try
        	{
        		return ArticleDAL.IsExist(articleId);
        	}
        	catch
        	{
#if DEBUG
				throw;
#else
				throw new Exception("检查文章记录出错");
#endif
        	}
        }
        
        /// <summary>
        /// 搜索文章
        /// </summary>
        /// <param name="conditions">搜索条件</param>
        /// <param name="pageSize">每页显示记录数</param>
        /// <param name="currentPage">当前页</param>
        /// <returns>搜索结果</returns>
        public static DataPaging<Article> List(Dictionary<string, string> queryParams, ushort pageSize, int currentPage)
        {
            DataPaging<Article> result = null;

            try
            {
                result = ArticleDAL.List(queryParams, pageSize, currentPage, null);
            }
            catch
            {
#if DEBUG
                throw;
#else
                throw new Exception("搜索文章出错");
#endif
            }

            return result;
        }

        /// <summary>
        /// 获取同分类下的下一篇文章
        /// </summary>
        /// <param name="refArticle">参照文章</param>
        /// <returns>同分类下的下一篇文章</returns>
        public static Article GetNextOf(Article refArticle)
        {
            return ArticleDAL.GetAdjacent(refArticle, true, MinVisibleArticleWeight);
        }

        /// <summary>
        /// 获取同分类下的上一篇文章
        /// </summary>
        /// <param name="refArticle">参照文章</param>
        /// <returns>同分类下的上一篇文章</returns>
        public static Article GetPreviousOf(Article refArticle)
        {
            return ArticleDAL.GetAdjacent(refArticle, false, MinVisibleArticleWeight);
        }

        /// <summary>
        /// 增加文章查看数
        /// </summary>
        /// <param name="articleId">文章编号</param>
        public static void AddViewCount(int articleId)
        {
            try
            {
                ArticleDAL.AddViewCount(articleId);
            }
            catch
            {
#if DEBUG
                throw;
#else
                throw new Exception("更新文章出错");
#endif
            }
        }

        /// <summary>
        /// 按分类列出文章，每页10篇
        /// </summary>
        /// <param name="categoryId">分类编号</param>
        /// <param name="currentPage">当前页</param>
        /// <returns>文章列表</returns>
        public static DataPaging<Article> ListByCategory(int categoryId, int currentPage)
        {
            var cacheName = String.Format(CACHENAME_INDEX, categoryId);
            DataPaging<Article> result = null;

            if (currentPage == 1)
            {
                result = HttpContext.Current.Cache[cacheName] as DataPaging<Article>;
            }

            if (result == null)
            {
                try
                {
                    result = ArticleDAL.ListByCategory(categoryId, MinVisibleArticleWeight, 10, currentPage);
                }
                catch
                {
#if DEBUG
                    throw;
#else
                    throw new Exception("读取文章目录出错");
#endif
                }

                if (result != null && currentPage == 1)
                {
                    HttpContext.Current.Cache.Add(cacheName, result,
                        null, DateTime.Now.AddMinutes(15), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
                }
            }

            return result;
        }

        /// <summary>
        /// 获取按查看数排序的文章列表
        /// </summary>
        /// <param name="categoryId">分类编号</param>
        /// <returns>文章列表</returns>
        public static Article[] GetTopView(int categoryId)
        {
            var cacheName = String.Format(CACHENAME_TOPVIEW, categoryId);
            var result = HttpContext.Current.Cache[cacheName] as Article[];

            if (result == null)
            {
                try
                {
                    result = ArticleDAL.GetTopView(categoryId, MinVisibleArticleWeight, 10);
                }
                catch
                {
#if DEBUG
                    throw;
#else
                    throw new Exception("获取文章阅读排行出错");
#endif
                }

                if (result != null)
                {
                    HttpContext.Current.Cache.Add(cacheName, result,
                        null, DateTime.Now.AddMinutes(15), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
                }
            }

            return result;
        }

        /// <summary>
        /// 获取按权重、发表时间反序排列的推荐文章列表（权重200以上）
        /// </summary>
        /// <returns>推荐文章列表</returns>
        public static Article[] GetRecommends()
        {
            var result = HttpContext.Current.Cache[CACHENAME_RECOMMENDS] as Article[];

            if (result == null)
            {
                try
                {
                    result = ArticleDAL.GetByMinWeight(MinRecommendArticleWeight);
                }
                catch
                {
#if DEBUG
                    throw;
#else
                    throw new Exception("获取推荐文章出错");
#endif
                }

                if (result != null)
                {
                    HttpContext.Current.Cache.Add(CACHENAME_RECOMMENDS, result,
                        null, DateTime.Now.AddMinutes(15), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
                }
            }

            return result;
        }
    }
}
